package com.dyava.dycache.redis;

import com.alibaba.fastjson.JSON;
import com.dyava.dycache.core.CacheDefined;
import com.dyava.dycache.core.CacheEngine;
import com.dyava.dycache.core.CacheEngineContext;
import com.dyava.dycache.core.CacheWrap;
import org.apache.commons.lang3.StringUtils;

/**
 * Created by jjliu on 2020/4/9.
 */
public class RedisCacheEngine extends CacheEngine {

    RedisClient redisClient;

    public RedisClient getRedisClient() {
        return redisClient;
    }

    public void setRedisClient(RedisClient redisClient) {
        this.redisClient = redisClient;
    }

    @Override
    protected String getCacheVersion(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        String version = redisClient.readVersion(key);
        return StringUtils.defaultIfBlank(version,null);
    }

    protected  CacheWrap _toCacheWrap(RedisCacheWrap redisCacheWrap, CacheDefined cacheDefined){
        if(redisCacheWrap==null){
            return null;
        }else{
            Object data = null;
            if(redisCacheWrap.getData()!=null){
                data = JSON.parseObject(redisCacheWrap.getData(),cacheDefined.getType());
            }
            CacheWrap cw = new CacheWrap(data,redisCacheWrap.getExpireAt(),redisCacheWrap.getVersion());
            return cw;
        }
    }
    protected  RedisCacheWrap _toRedisCacheWrap(CacheWrap cacheWrap, CacheDefined cacheDefined){
        String data = null;
        if(cacheWrap.getData()!=null){
            data = JSON.toJSONString(cacheWrap.getData());
        }
        RedisCacheWrap rcw = new RedisCacheWrap(data,cacheWrap.getExpireAt(),cacheWrap.getVersion());
        return rcw;
    }


    @Override
    protected  CacheWrap getCacheWrap(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        RedisCacheWrap redisCacheWrap = redisClient.read(key);
        CacheWrap cw = _toCacheWrap(redisCacheWrap,cacheDefined);
        return cw;
    }

    @Override
    protected  CacheWrap waitCacheWrap(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        boolean hasLocked = redisClient.lock(key);
        try{
            RedisCacheWrap redisCacheWrap = redisClient.read(key);
            CacheWrap cw = _toCacheWrap(redisCacheWrap,cacheDefined);
            return cw;
        }finally {
            if(hasLocked){
                redisClient.unLock(key);
            }
        }
    }

    @Override
    protected void deleteCache(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        redisClient.delete(key);
    }

    @Override
    protected  void saveCacheWrap(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id, CacheWrap cacheWrap) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        RedisCacheWrap redisCacheWrap = _toRedisCacheWrap(cacheWrap,cacheDefined);
        redisClient.write(key,redisCacheWrap);
    }

    @Override
    protected boolean tryLock(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        return redisClient.tryLock(key);
    }

    @Override
    protected void unLock(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id) {
        String key = generateKey(cacheEngineContext,cacheDefined,id);
        redisClient.unLock(key);
    }
}
